package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.page.PointsBoardQuery;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.TableInfoContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;
import static com.tianji.learning.constants.RedisConstants.POINTS_BOARD_KEY_PREFIX;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author ffk
 * @since 2024-07-01
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {

    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;

    /**
     * 分页查询积分榜单
     * @param pointsBoardQuery
     * @return 排名，积分值，上榜用户信息集合
     */
    @Override
    public PointsBoardVO pageQueryBoard(PointsBoardQuery pointsBoardQuery) {
        PointsBoardVO pointsBoardVO = new PointsBoardVO();

        String key=POINTS_BOARD_KEY_PREFIX + LocalDate.now().format(DateUtils.POINTS_DATE_SUFFIX_FORMATTER );
//        Double score = redisTemplate.opsForZSet().score(key, UserContext.getUser());
//        pointsBoardVO.setPoints(score.intValue());


        Boolean flag= pointsBoardQuery.getSeason()==null||pointsBoardQuery.getSeason()==0;
        //当前用户数据
        PointsBoard myMsg = flag? findCurrentSeasonUserMsg(key) : findHistorySeasonUserMsg(pointsBoardQuery.getSeason());

        //榜单数据
        List<PointsBoard> pointsBoardMsg = flag?
                findCurrentSeasonBoardMsg(pointsBoardQuery.getPageNo(),pointsBoardQuery.getPageSize(),key)
                : findHistorySeasonBoardMsg(pointsBoardQuery);


        //我的
        if(ObjectUtils.isNotEmpty(myMsg)){
            pointsBoardVO.setRank(myMsg.getRank());
            pointsBoardVO.setPoints(myMsg.getPoints());
        }

        //上榜人信息集合
        List<PointsBoardItemVO> voList=new ArrayList<>();
        pointsBoardVO.setBoardList(voList);

        if(ObjectUtils.isEmpty(pointsBoardMsg)){
            return pointsBoardVO;
        }

        //我可能不在榜单，收集id
        Set<Long> userIds = pointsBoardMsg.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        userIds.add(UserContext.getUser());

        //查姓名
        List<UserDTO> userInfo = userClient.queryUserByIds(userIds);
        Map<Long, String> userMap =new HashMap<>(userInfo.size());
        if(ObjectUtils.isNotEmpty(userInfo)){
            userMap = userInfo.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        }

        //填充数据
        for (PointsBoard pointsBoard : pointsBoardMsg) {
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            itemVO.setRank(pointsBoard.getRank());
            itemVO.setName(userMap.get(pointsBoard.getUserId()));
            itemVO.setPoints(pointsBoard.getPoints());

            voList.add(itemVO);
        }

        return pointsBoardVO;
    }

    /**
     * 创建表
     * @param season
     */
    private  final PointsBoardMapper pointsBoardMapper;
    @Override
    public void createPointsBoardTableBySeason(Integer season) {
        pointsBoardMapper.createPointsBoardTableBySeason(POINTS_BOARD_TABLE_PREFIX+season);
    }



    //查询历史榜单
    private List<PointsBoard> findHistorySeasonBoardMsg(PointsBoardQuery pointsBoardQuery) {
        Long season = pointsBoardQuery.getSeason();
        Page<PointsBoard> page = this.lambdaQuery().page(pointsBoardQuery.toMpPage());

        List<PointsBoard> records = page.getRecords();
        if(ObjectUtils.isEmpty(records)){
            log.info("这个赛季{}的数据没有啊",season);
            return Collections.emptyList();
        }

        for (PointsBoard record : records) {
            record.setRank(record.getId().intValue());
        }

        return records;
    }

    //查询该用户历史信息
    private PointsBoard findHistorySeasonUserMsg(Long season) {
        Long userId = UserContext.getUser();

        TableInfoContext.setInfo(POINTS_BOARD_TABLE_PREFIX+season);

        PointsBoard myHistory = this.lambdaQuery()
                .eq(PointsBoard::getUserId, userId)
                .one();

        if(ObjectUtils.isEmpty(myHistory)){
            log.info("在第{}赛季，用户id:{}的信息没得啊",season,userId);
            return null;
        }

        myHistory.setRank(myHistory.getId().intValue());

        return myHistory;
    }

    /**
     *查询当前赛季排行榜
     */
    public List<PointsBoard> findCurrentSeasonBoardMsg(Integer pageNo, Integer pageSize, String key) {

        //0 19 20 39
        int start=(pageNo-1)*pageSize;
        int end=start+pageSize-1;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);

        List<PointsBoard> voList=new ArrayList<>(typedTuples.size());

        int rank=start+1;//start是下标
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {

            Long userId = Long.valueOf(typedTuple.getValue());
            Double score = typedTuple.getScore();
            if(userId==null || score == null){
                continue;
            }

            PointsBoard pointsBoard = new PointsBoard();
            pointsBoard.setUserId(userId);
            pointsBoard.setPoints(score.intValue());
            pointsBoard.setRank(rank++);
            voList.add(pointsBoard);
        }
        return voList;
    }

    /**
     * 查询当前赛季用户的排名信息
     */
    private PointsBoard findCurrentSeasonUserMsg(String key) {
        PointsBoard pointsBoard = new PointsBoard();

        BoundZSetOperations<String, String> ops= redisTemplate.boundZSetOps(key);

        Long userid = UserContext.getUser();
        Long rank = ops.reverseRank(userid.toString());
         Double score = ops.score(userid.toString());


        pointsBoard.setRank(rank==null? 0 : rank.intValue()+1);//下标加一
        pointsBoard.setPoints(score==null ? 0 : score.intValue());

        return pointsBoard;
    }

}
